﻿using System;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Windows.Data;
using Red.Controls.TimeLine.Core;
using Red.Controls.TimeLine.Utils;

namespace Red.Controls.TimeLine.TracksTree
{
    public class TimePanel : Panel
    {
        public TimePanel()
        { 
            ClipToBounds = true;

            Binding binding = new Binding( "TimeLineControler" );
            binding.RelativeSource = new RelativeSource( RelativeSourceMode.FindAncestor, typeof( TimeLine ), 1 );
            SetBinding( TimeLineControlerProperty, binding );
        }

        #region Attached properties

        public static readonly DependencyProperty TimeProperty =
            DependencyProperty.RegisterAttached( "Time", typeof( double ), typeof( TimePanel ),
                new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, OnTimePropertyChanged ) );      

        public static double GetTime( DependencyObject d )
        {
            return (double)d.GetValue( TimeProperty );
        }

        public static void SetTime( DependencyObject d, double value )
        {
            d.SetValue( TimeProperty, value );
        }

        private static void OnTimePropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs args )
        {
            TimePanel panel = VisualTreeUtils.FindParent<TimePanel>( obj );
            if ( panel != null )
            {
                panel.InvalidateArrange();
            }
        }

        #endregion

        #region Dependency properties

        public TimeLineControler TimeLineControler
        {
            get { return (TimeLineControler)GetValue( TimeLineControlerProperty ); }
            set { SetValue( TimeLineControlerProperty, value ); }
        }

        public static readonly DependencyProperty TimeLineControlerProperty =
            DependencyProperty.Register( "TimeLineControler", typeof( TimeLineControler ), typeof( TimePanel ),
                new PropertyMetadata( null, OnTimeLineControlerChange ) );

        private static void OnTimeLineControlerChange( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            TimePanel panel = (TimePanel)d;

            TimeLineControler oldControler = (TimeLineControler)e.OldValue;
            TimeLineControler newControler = (TimeLineControler)e.NewValue;

            if ( oldControler != null )
            {
                oldControler.StateChanged -= panel.OnTimeControlerStateChanged;
            }

            if ( newControler != null )
            {
                newControler.StateChanged += panel.OnTimeControlerStateChanged;
            }
        }

        private void OnTimeControlerStateChanged( object sender, EventArgs e )
        {
            InvalidateVisual();
            InvalidateArrange();
        }



        public Brush InvalidRegionBrush
        {
            get { return (Brush)GetValue( InvalidRegionBrushProperty ); }
            set { SetValue( InvalidRegionBrushProperty, value ); }
        }

        // Using a DependencyProperty as the backing store for InvalidRegionBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InvalidRegionBrushProperty =
            DependencyProperty.Register( "InvalidRegionBrush", typeof( Brush ), typeof( TimePanel ), 
                new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender ) );

        #endregion

        #region Draw background
        /*
        protected override void OnRender( DrawingContext dc )
        {
            if ( TimeLineControler == null )
            {
                base.OnRender( dc );
                return;
            }

            Brush invalidRegionBrush = InvalidRegionBrush;
            if ( invalidRegionBrush != null )
            {
                dc.DrawRectangle( invalidRegionBrush, null, new Rect( 0, 0, base.ActualWidth, base.ActualHeight ) );
            }

            if ( Background != null )
            {
                double minValue = TimeLineControler.MinTimeLineValue;
                double maxValue = TimeLineControler.MaxTimeLineValue;

                bool maxVisible = IsValueVisibleOnScreen( maxValue );
                bool minVisible = IsValueVisibleOnScreen( minValue );

                if ( maxVisible && minVisible )
                {
                    double maxXPosition = ValueToScreenOffset( maxValue );
                    double minXPosition = ValueToScreenOffset( minValue );

                    dc.DrawRectangle( Background, null, new Rect( minXPosition, 0, maxXPosition - minXPosition, base.ActualHeight ) );
                }
                else if ( maxVisible )
                {
                    double maxXPosition = ValueToScreenOffset( maxValue );

                    dc.DrawRectangle( Background, null, new Rect( 0, 0, maxXPosition, base.ActualHeight ) );
                }
                else if ( minVisible )
                {
                    double minXPosition = ValueToScreenOffset( minValue );

                    dc.DrawRectangle( Background, null, new Rect( minXPosition, 0, base.ActualWidth, base.ActualHeight ) );
                }
            }
        }

        private double ValueToScreenOffset( double value )
        {
            return TimeLineControler.TimeToScreenOffset( value );
        }

        private double GetCurrentEndValue()
        {
            return ( TimeLineControler.StartTime + ( base.ActualWidth / TimeLineControler.MajorIntervalSizePx ) ) * TimeLineControler.MajorIntervalUnit;
        }

        private bool IsValueVisibleOnScreen( double value )
        {
            if ( ( value < TimeLineControler.StartTime ) && ( GetCurrentEndValue() >= value ) )
            {
                return false;
            }
            return true;
        }
        */
        #endregion

        protected override Geometry GetLayoutClip( Size layoutSlotSize )
        {
            return new RectangleGeometry( new Rect( RenderSize ) );
        }

        protected override Size MeasureOverride( Size constraint )
        {
            Size childConstraint = new Size( Double.PositiveInfinity, constraint.Height );

            foreach ( UIElement child in InternalChildren )
            {
                child.Measure( childConstraint );
            }

            return new Size();
        }

        protected override Size ArrangeOverride( Size arrangeSize )
        {
            if ( TimeLineControler == null )
            {
                return arrangeSize;
            }

            foreach ( UIElement child in InternalChildren )
            {
                double time = GetTime( child );

                double x = TimeLineControler.TimeToScreenOffset( time );
                child.Arrange( new Rect( new Point( x, 0 ), arrangeSize ) );
            }

            return arrangeSize;            
        }
    }

}
